home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Revolution - Das Atari CD Magazin 1997
/
Revolution - Das Atari CD Magazin 1.iso
/
software
/
anwendng
/
clix360
/
doc
/
udo
/
hm2
/
haenisch.ui
Wrap
Text File
|
1997-01-21
|
59KB
|
1,635 lines
#-----------------------------------------------------------------
# Hänisch-Modula
#-----------------------------------------------------------------
!node Hänisch-Modula-2
!subtoc [html, stg]
#*****************************************************************
!subnode Laufzeitfehler
Laufzeitfehler führen zu sogenannten Exceptions des Prozessors. Das HM2
Laufzeitsystem verändert normalerweise keine Systemvektoren, sodaß ein
Laufzeitfehler ohne weitere Maßnahmen zum Absturz des Programms führt.
Die Kontrolle darüber, was bei einem Laufzeitfehler geschehen soll,
liegt voll beim Programmierer. Der einfachste Weg, auf Laufzeitfehler zu
reagieren, ist der Import des Moduls [Rts]. Ist dieses Modul zum
Programm gelinkt, so wird das Programm per Default bei einem
Laufzeitfehler terminiert (wobei die Terminierungskette abgearbeitet
wird). Durch Installation einer geeigneten Prozedur sind mit diesem
Modul aber auch andere Reaktionen auf Laufzeitfehler möglich.
Falls das Programm unter dem Runtime Debugger (RTD) gestartet wird,
werden selbstverständlich alle Exceptions abgefangen und Laufzeitfehler
im Klartext ausgegeben, auch wenn das Modul Rts nicht gelinkt ist.
Wird das Programm von (!PRG) aus als Testprogramm gestartet, so besteht
bei einem Laufzeitfehler die Möglichkeit, einen Dump zu schreiben, der
dann mit dem Post Mortem Debugger (PMD) analysiert werden kann. Dazu muß
in (!PRG) die Option 'Dump-Option für TEST-Programm' aktiviert sein und
das Modul Rts muß zum Testprogramm gelinkt sein.
#*****************************************************************
!subnode Bedingte Compilierung
Bedingte Compilierung ermöglicht es, Teile des Sourcetextes abhängig von
einer Bedingung zu compilieren. Das ist z.B. praktisch, um von einem
Programm verschiedene Versionen zu erzeugen (z.B. eine Version mit
eingschränktem Funtionsumfang oder eine Version mit Debug-Ausgaben).
Dazu wird der betreffende Abschnitt des Sourcetextes in
Kommentarklammern gesetzt und durch '$? <konstanter boolscher Ausdruck>
:' eingeleitet. Beispiel:
!begin_verbatim
CONST
compile = TRUE;
BEGIN
(* $? compile:
(* Dieser Bereich wird nur dann übersetzt, wenn compile
den Wert TRUE hat *)
WriteString ('Die Konstante compile hat den Wert TRUE');
*)
!end_verbatim
Falls der boolsche Ausdruck den Wert FALSE hat, so wird der geklammerte
Bereich als Kommentar angesehen.
Um verschiedene Versionen eines Programms zu verwalten, bietet sich die
Verwendung der Makevariable FLAG an (der Wert dieser Variable kann im
Optionendialog bei Flag eingestellt werden). Damit kann in Abhängigkeit
von SYSTEM.FLAG eine Version definiert werden. Beispiel:
!begin_verbatim
DEFINITION MODULE Base;
IMPORT SYSTEM;
CONST
Full = SYSTEM.FLAG = 0;
Demo = SYSTEM.FLAG = 1;
!end_verbatim
Je nach Wert der Makevariablen FLAG wird nun beim Compileren des
Definitionsmoduls der Wert von Full und Demo festgelegt. In Abhängigkeit
von diesem Wert können in anderen Modulen mittels bedingter Compilierung
Teile übersetzt werden oder nicht.
!begin_verbatim
IMPORT Base;
(*$? Base.Demo:
WriteString ('Dies ist die Demoversion');
*)
(*$? Base.Full:
WriteString ('Dies ist die Vollversion');
*)
!end_verbatim
Neben der bedingten Compilierung abhängig von einem boolschen Ausdruck
gibt es auch die bedingte Compilierung abhängig von einer Option. Dazu
wird der Bereich durch '$! X±:' eingeleitet, wobei X für eine beliebige
Compiler-Option steht (nicht nur Großbuchstabe) und '±' für '+' oder
'-'. Beispiel:
!begin_verbatim
(* $!2+:
(* Dieser Bereich wird übersetzt,
falls die Option 2 aktiviert ist
WriteString ('Das Programm läuft nur auf MC68020/30/40');
(* $!2-:
(* Dieser Bereich wird übersetzt,
falls die Option 2 nicht aktiviert ist
WriteString ('Das Programm läuft auch auf einem MC68000');
!end_verbatim
#*****************************************************************
!subnode Compiler-Optionen
Die Compiler-Optionen, auch Schalter genannt, beeinflussen das Verhalten
des Compilers in Bezug auf Überprüfungen und Codeerzeugung.
Sie können global im Optionen-Dialog oder für einzelne Module direkt im
Source-Text gesetzt werden. Im Source-Text können allerdings nur die
Optionen mit einem Großbuchstaben gesetzt werden. Sie stehen in
Kommentaren und werden durch ein '$'-Zeichen eingeleitet, gefolgt von
einem Großbuchstaben und '+', '-' oder '=':
!stg @autorefoff
!begin_itemize
!item (*$X+*) aktiviert die Option X,
!item (*$X-*) deaktiviert sie
!item (*$X=*) restauriert den Zustand vor der letzten Änderung.
!end_itemize
!stg @autorefon
Um eine Option auf einen bestimmten Bereich (z.B. eine Prozedur) zu
beschränken, sollte man am Ende dieses Bereichs die Option mittels der
'='-Variante auf den alten Zustand zurücksetzen. Diese Zeichenfolgen ($,
Großbuchstabe, +/-/=) werden an beliebiger Stelle innerhalb eines
Kommentars als Option interpretiert. Es können also auch mehrere
Optionen in einem Kommentar gesetzt werden und die Kommentarklammern
müssen die Optionen nicht direkt umschließen:
!stg @autorefoff
Beispiel: (* $K+ $B+ $E+$D- *)
!stg @autorefon
In geschachtelten Kommentaren werden sie jedoch nicht interpretiert; sie
können also auch auskommentiert werden.
!subsubtoc [stg, html]
#*****************************************************************
!subsubnode Option Initialiserung $I
!stg @alabel $I
Diese Option erzeugt als Debughilfe besonderen Code bei jedem BEGIN: für
Prozeduren wird der Platz der lokalen Variablen mit -1 initialisiert,
für den Modulrumpf werden die globalen Variablen mit -1 belegt. Dadurch
lassen sich uninitialisierte Variablen, insbesondere POINTER, leicht
entdecken, da ein Vergleich auf NIL fehlschlägt und ein Zugriff einen
Adreßfehler (Exception #3) auslöst und danach mit den Debuggern leicht
lokalisiert werden kann.
#*****************************************************************
!subsubnode Option Stacktest $S
!stg @alabel $S
Ist die S-Option aktiv, so wird bei Prozedureintritt ein Stacktest
durchgeführt. Ohne Überprüfung könnte der Stack in einen Daten- oder
Codebereich einer anderen Routine wachsen. Ein Stack-Überlauf führt zu
einem Laufzeitfehler.
#*****************************************************************
!subsubnode Option Overflow $V
!stg @alabel $V
Ist diese Option aktiviert, so wird bei arithmetischen Operationen ein
Überlaufstest durchgeführt und im Fehlerfall ein Laufzeitfehler
erzeugt.
#*****************************************************************
!subsubnode Option Rangetest $T
!stg @alabel $T
Ist diese Option aktiviert, so wird bei Zuweisungen, Parameterübergaben
und Array-Indizierungen ein Bereichstest durchgeführt. Eine
Bereichsüberschreitung führt zu einem Laufzeitfehler.
#*****************************************************************
!subsubnode Option Statische Checks $X
!stg @alabel $X
Durch Ausschalten dieser Option können statische Checks während der
Übersetzung deaktiviert werden. In diesem Fall werden auch die über
$T+ aktivierten Rangechecks abgeschaltet. Der erzeugte Code wird
nicht beeinflußt. Bei eingeschalteter Option wird u.a. entdeckt, wenn
einer SHORTCARD-Variablen eine negative Konstante zugewiesen oder bei
einem Array auf ein ungültiges Element zugegriffen wird (bei konstantem
Index). Wird bei einer BITSET-Variablen mittels IN geprüft, ob eine
Konstante kleiner 0 oder größer 15 enthalten ist, so kommt es ebenfalls
zu einer Fehlermeldung. Dies gilt analog für alle Mengen-Variablen.
Letzteres führt übrigens nie zu einem Laufzeitfehler, sondern liefert
korrekterweise einfach FALSE. Übersetzen kann man diese Anweisung nur
mit $X-, generiert wird dann direkt FALSE. Außerdem wird über diese
Option die Überprüfung der Existenz einer RETURN-Anweisung in einer
Funktionsprozedur abgeschaltet.
#*****************************************************************
!subsubnode Option Laufzeitüberprüfungen $Y
!stg @alabel $Y
Über diese Option werden verschiedene Laufzeitüberprüfungen aktiviert.
Zum einen handelt es sich dabei um die Überprüfung des RETURN-Statements
einer Funktionsprozedur. Wird eine solche fälschlicherweise nicht über
RETURN verlassen, so führt dies zu einem Laufzeitfehler. Zum anderen
findet eine Überprüfung der CASE-Anweisung statt. Kommt es in einem
CASE-Statement ohne ELSE zu einer Variante, die nicht abgefragt wird, so
wird ein Laufzeitfehler ausgelöst. Schließlich wird überprüft, ob in
einer FORM-Zuweisung das Ziel unerlaubterweise als Folgeparameter
auftritt:
!begin_verbatim
str := FORM(str,' Suffix'); (* erlaubt *)
str := FORM('Präfix ',str); (* Laufzeitfehler *)
!end_verbatim
#*****************************************************************
!subsubnode Option Warnungen $Q
!stg @alabel $Q
Bei Aktivierung dieser Option werden Warnungen unterdrückt.
#*****************************************************************
!subsubnode Option Hänisch-Spezifika $H
!stg @alabel $H
Diese Option mindert die Akzeptanz für Hänisch-Modula-spezifische
Konstrukte: die Verwendung von BREAK, CONTINUE, FORM, STRING, VOID,
Pointer-INC/DEC usw. liefert dann eine Warnung.
#*****************************************************************
!subsubnode Option Nullterminierte Strings $G
!stg @alabel $G
Ist diese Option aktiviert, so geht der Compiler von 0C-terminierten
Strings aus (im Unterschied zu HIGH-Wert-terminierten). Bei
eingeschalteter Option $G+ wird dann z.B.
!begin_verbatim
VAR str: ARRAY[0..4] OF CHAR;
...
s := 'Hallo';
!end_verbatim
als Fehler gemeldet, da in str kein abschließendes 0C hineinpaßt.
#*****************************************************************
!subsubnode Option WORD-Breite $W
!stg @alabel $W
Diese Option bezieht sich auf die Speicherbelegung von Aufzählungs-,
Unterbereichs- und Mengentypen. Für diese Typen wird normalerweise
ein kleinstmöglicher Speicher in Byte-Schritten reserviert. Mit der
W-Option kann der kleinste Speicherbereich auf zwei Bytes gesetzt
werden.
#*****************************************************************
!subsubnode Option LONG-Breite $L
!stg @alabel $L
Diese Option betrifft die Speicherbelegung von Aufzählungs-,
Unterbereichs- und Mengentypen. Für diese Typen wird normalerweise
ein kleinstmöglicher Speicher in Byte-Schritten reserviert. Mit der
L-Option kann der kleinste Speicherbereich auf vier Bytes gesetzt
werden.
#*****************************************************************
!subsubnode Option Prozedur-Prolog und -Epilog $P
!stg @alabel Epilog
!stg @alabel Prolog
!stg @alabel $P
Wird diese Option eingeschaltet, so wird für Prozeduren kein Prolog und
Epilog erzeugt. Prolog und Epilog dienen v. a. zum Retten und
Restaurieren von Registern und zum Anlegen eines lokalen
Variablenbereichs. Auch Stackcheck ($S+) und Initialisierung der
Variablen ($I+) erfolgen im Prolog.
#*****************************************************************
!subsubnode Option Eintrittscode $E
!stg @alabel $E
Für exportierte Prozeduren wird ein besonderer Eintritts-Code erzeugt.
Prozedur-Variablen und Prozedur-Parameter dürfen nur Prozeduren
zugewiesen werden, die diesen Eintritts-Code enthalten. Die Erzeugung
des Eintritts-Codes kann mit dieser Option eingeschaltet werden. Ist
gleichzeitig P eingeschaltet, so wird kein Eintritts-Code erzeugt, die
Prozedur kann aber für Variablen und Parameter benutzt werden.
#*****************************************************************
!subsubnode Option Main-Modul $M
!stg @alabel $M
Diese Option verhindert, daß ein Modul beim optimierenden Linken
gegebenenfalls vollständig entfernt wird. Dies ist nötig, wenn das Modul im
Modulrumpf Initialisierungen vornimmt, die auch dann benötigt werden, wenn
keine Variable oder Prozedur des Moduls von anderen Modulen benutzt wird.
#*****************************************************************
!subsubnode Option Registervariable $R oder $Reg
!stg @alabel $R
!stg @alabel $Reg
Die nächste Variable wird in einem Register gehalten. Voraussetzung ist,
daß sie nicht breiter als 32-Bit ist und lokal in einer Prozedur
deklariert wurde. Bei aktivierter Option <f> können Fließkommavariablen
in FPU-Registern gehalten werden. Diese Option wird automatisch
zurückgesetzt. Wenn eine Deklaration der Form
!begin_verbatim
(*$Reg*) n, m: INTEGER;
!end_verbatim
verwendet wird, bezieht sich die Option $Reg nur auf die Variable <n>.
Die nächste Variable (im Beispiel <m>) würde wieder normal im Speicher
gehalten werden. POINTER-Variablen werden in Adreßregister gelegt,
REAL-Variablen bei aktivierter Option <f> in FPU-Register.
N.B.: Bei den Direktiven $R, $Reg, $RD, $R4 und $RTE wird kein
anschließendes "+", "-" oder "=" erwartet.
#*****************************************************************
!subsubnode Option Datenregister $RD oder $RData
!stg @alabel $RD
!stg @alabel $RData
Mittels $RD kann man ein Datenregister verlangen, z.B. wenn kein
Adreßregister mehr zur Verfügung steht oder eine SHORTREAL-Variable bei
aktivierter Option <f> in ein Datenregister gelegt werden soll:
!begin_verbatim
(*$RD*) ptr: POINTER TO CHAR;
(*$RD*) val: SHORTREAL;
!end_verbatim
N.B.: Bei den Direktiven $R, $Reg, $RD, $R4 und $RTE wird kein
anschließendes "+", "-" oder "=" erwartet.
#*****************************************************************
!subsubnode Option Adreßregister A4 $R4
!stg @alabel $R4
Mittels $R4 kann man bei aktivierter Option statt einem Adreßregister
ein Datenregister wählen. (Bei aktivierter Option <4> steht A4 nicht zur
Verfügung.)
N.B.: Bei den Direktiven $R, $Reg, $RD, $R4 und $RTE wird kein
anschließendes "+", "-" oder "=" erwartet.
#*****************************************************************
!subsubnode Option Return From Exception $RT oder $RTE
!stg @alabel $RT
!stg @alabel $RTE
Diese Variante bezieht sich nicht auf Variablen, sondern auf Prozeduren:
sie schlieβt die nächste bzw. aktuelle Prozedur (und nur diese) mit RTE
statt RTS ab (Test am Ende der Prozedur), aber nur dann, wenn diese
Prozedur tatsächlich mit RTS abschlieβe, also parameterlos, $K+ oder
ähnliches ist.
N.B.: Bei den Direktiven $R, $Reg, $RD, $R4, $RO und $RTE wird kein
anschließendes "+", "-" oder "=" erwartet.
#*****************************************************************
!subsubnode Option ReadOnly-Variablen $RO
!stg @alabel $RO
!stg @alabel "ReadOnly-Variablen"
Die Direktive $RO erlaubt die Deklaration von ReadOnly-Variablen und
Parametern. $RO muβ wie $Reg vor den Namen der Variable gesetzt werden
und gilt nur für eine Variable. Sinnvoll ist die Direktive vor allem für
Referenzparameter und Variablen in Definitions (diese können im
zugehörigen Implementation verändert werden, andere Module können sie
nur lesen). Auch in der formalen Parameterliste eines Prozedurtyps wird
die Direktive unterstützt; sie muβ dort vor dem jeweiligen Typnamen
stehen.
N.B.: Bei den Direktiven $R, $Reg, $RD, $R4, $RO und $RTE wird kein
anschließendes "+", "-" oder "=" erwartet.
#*****************************************************************
!subsubnode Option Real-Rückgabe $R0
!stg @alabel $R0
Bei aktivierter Option <f> (Coprozessor) werden REAL-Funktionsergebnisse
normalerweise in FP0 zurückgegeben. Mittels der Option $R0 kann dies
unterbunden werden (Default: $R0+); dann erfolgt die Rückgabe in D0 bzw.
D0/D1. Die Art der Rückgabe gehört zum Prozedurtyp.
#*****************************************************************
!subsubnode Option Scratchregister $R1
!stg @alabel $R1
Die Option $R1+ veranlaßt, daß auch Scratchregister im
Prozedurprolog/-epilog gesichert und restauriert werden.
#*****************************************************************
!subsubnode Option Registerrettung $R2
!stg @alabel $R2
Die Option $R2+ veranlaßt im Prozedurtyp, daß vor Aufruf einer
entsprechenden Prozedur ggf. die Register D2/A2/FP1/FP2 gerettet und
nach Rückkehr restauriert werden. Dieser Status gehört zum Prozedurtyp.
Sinn dieser Option ist der Aufruf externer Routinen (z.B. per
Cookie-Tabelle), die diese Register als Scratchregister ansehen.
#*****************************************************************
!subsubnode Option Stack-Korrektur $K
!stg @alabel $K
!stg @alabel Stack-Korrektur
Diese Option steuert, ob der Rufer einer Prozedur oder die Prozedur
selbst die übergebenen Parameter wieder vom Stack entfernt. Bei
eingeschalteter Option nimmt der Rufer die Korrektur vor. Nach jedem
Prozeduraufruf wird also entsprechender Code erzeugt. Bei
ausgeschalteter Option übernimmt die gerufene Prozedur diese Korrektur
selbst, was i.a. eine Codeverkürzung bewirkt, da die Prozedur selbst
dadurch zwar einige wenige Bytes länger wird, bei jedem Aufruf aber 2
bis 4 Bytes gespart werden. Bei eingeschalteter Option <2> kann eine
Prozedur unter Verwendung der RTD-Instruktion verlassen werden, sodaß
der Code nie länger wird.
Die Stellung des K-Schalters ist Teil des Prozedurtyps. Dieser wird beim
Übersetzen einer Prozedurtyp-Deklaration oder der Prozedurköpfe eines
DEFINITION MODULEs festgelegt.
Im IMPLEMENTATION MODULE muß die Stellung der Option für jede Prozedur
übereinstimmen und nur Prozedurtypen mit gleicher Stack-Korrektur sind
kompatibel. Gegebenenfalls wird ein Fehler gemeldet. Allerdings ist die
Aktivierung dieser Option nur sehr selten nötig.
Notwendig ist sie z.B. bei objc.tUserProc, da das AES davon ausgeht, daß
es den Stack selbst korrigieren muß.
#*****************************************************************
!subsubnode Option BYTE-Werteparameter $B
!stg @alabel $B
Diese Option steuert die Übergabe von Byte-Werteparametern, also z.B.
Parameter des Typs CHAR oder BOOLEAN. Bei eingeschalteter Option wird
der Parameter zu einem Wort ausgedehnt und als solches übergeben (der
Parameter liegt dann an ungerader Adresse, das Füllbyte an gerader),
ansonsten als Byte (der Parameter liegt dann an gerader Adresse und das
Füllbyte an ungerader). Die Übergabe mit $B+ ist zeit- und
codeaufwendiger, kann jedoch bei direkter Parameterübergabe an das
Betriebssystem nötig sein.
#*****************************************************************
!subsubnode Option Debugging-Informationen $D
!stg @alabel $D
Diese Option ist per Default aktiv. Ist sie abgeschaltet, so erzeugt der
Compiler keine Zeileninformation für die Debugger. Dies ist wichtig für
Prozeduren, die als Datenbereich benutzt werden sollen.
Falls zusätzlich auch Option <d> aktiv ist, so wird der Debug-Code
älterer Compiler-Versionen erzeugt:
In den erzeugten Code des Programmes werden Debug-Informationen
eingesetzt. Nach jeder Modula-Anweisung wird die Zeilennummer im
Quelltext durch folgende Instruktionen abgelegt:
!begin_verbatim
BRA.S *+4 ;$6002
DC.W $A000 + Zeilennummer
!end_verbatim
Am Ende einer Prozedur oder eines Moduls wird deren Name abgelegt. Dazu
wird folgender Code erzeugt.
!begin_verbatim
RTS
BRA.S *+4 ;$6002
DC.W $A000
DC.B 'Name', 0 ;Name der Prozedur bzw. des Moduls
!end_verbatim
Die Zeilennummer wird also jeweils übersprungen, sodaß auch ein mit
diesem Debug-Code versehenes Programm normal lauffähig ist.
#*****************************************************************
# Linker
#*****************************************************************
!subnode Linker-Optionen
!subsubtoc [html, stg]
#*****************************************************************
!subsubnode Linkeroption <2> (mc68020)
Diese Option steuert, ob im erzeugten Programm Code für die Prozessoren
MC68020/30 enthalten sein darf oder nicht. Dies ist der Fall, wenn die
Option aktiv ist.
#*****************************************************************
!subsubnode Linkeroption <f> (Coprozessor)
Diese Option steuert, ob im erzeugten Programm Code für den mathematischen
Coprozessor MC68881/882 enthalten sein darf oder nicht. Dies ist der Fall,
wenn die Option aktiv ist.
#*****************************************************************
!subsubnode Linkeroption <4> (Reg. A4 sperren)
Diese Option steuert, ob im erzeugten Programm das CPU-Register A4
verwendet werden darf oder nicht. Ist die Option aktiviert, so darf A4
nicht verwendet werden. Dies ist nur für RTOS nötig, ansonsten unsinnig.
#*****************************************************************
!subsubnode Linkeroption <l> (LST-Datei)
Will man eine Übersicht über die beim optimierenden Linken entfernten
Prozeduren erhalten, so kann man über diese Option eine ASCII-Datei mit
der Extension .LST, die die Optimierungen protokolliert, mit folgendem
Format erzeugen:
!begin_verbatim
LST ::= {Module}.
Module ::= ModuleName EOL {DelProc} [HeadSave].
DelProc ::= Number " " ProcName EOL.
HeadSave ::= Number " (HT)" EOL.
Number - fünfstellige Dezimalzahl mit führenden Blanks.
!end_verbatim
#*****************************************************************
!subsubnode Linkeroption <s> (SYM-Datei)
!stg @alabel SYM-Datei
Ist diese Option aktiviert, so wird beim Linken eine SYM-Datei erzeugt.
Diese Datei wird von den Debuggern benötigt (vgl. <v>).
#*****************************************************************
!subsubnode Linkeroption <v> (Archive in SYM-Datei)
Die SYM-Datei enthält normalerweise nur Informationen zu Modulen, deren
Object (B-Datei) sich nicht in einem Archiv befindet. Ist zusätlich zu
<s> auch <v> aktiviert, so werden für alle Module Informationen in die
SYM-Datei geschrieben.
#*****************************************************************
!subnode Datentypen und deren Speicherbelegung
!stg @alabel Datentypen
!stg @alabel Speicherbelegung
Hänisch-Modula-2 kennt zwei Grundtypen für ganzzahlige Werte:
vorzeichenbehaftete und vorzeichenlose Typen. Innerhalb beider
Grundtypen gibt es Typen verschiedener Gröβe (ein, zwei oder vier Byte).
Alle diese Typen sind zuweisungskompatibel. Darüberhinaus sind innerhalb
eines Grundtyps alle Typen operatorkompatibel. Somit kann man z.B. (ohne
explizite Angabe einer Typkonvertierung) eine Variable vom Typ SHORTINT
an eine Variable vom Typ LONGCARD zuweisen (und umgekehrt) und auch die
Addition einer Variable vom Typ SHORTINT zu einer Variablen vom Typ
LONGINT ist möglich. Der Compiler erzeugt automatisch Code, falls eine
Typkonvertierung nötig ist. Optional kann auch Code für die
Bereichsüberschreitung bei solchen Operationen erzeugt werden.
Unterbereichstypen können explizit vorzeichenbehaftet oder vorzeichenlos
deklariert werden. Im folgenden Beispiel ist t1 vorzeichenbehaftet und t2
vorzeichenlos:
!begin_verbatim
TYPE
t1 = SHORTINT [1..20];
t2 = [1..20];
!end_verbatim
Analog sind die Typen SHORTREAL und LONGREAL zueinander operatorkompatibel.
!label CARDINAL
!label SHORTCARD
!label LONGCARD
!label INTEGER
!label SHORTINT
!label LONGINT
!label CHAR
!label BOOLEAN
!label POINTER
!label Unterbereich
!begin_verbatim
======================================================================
Typ Größe Wertebereich
----------------------------------------------------------------------
CARDINAL 2/4 vgl. SHORTCARD / LONGCARD und Option <w>
SHORTCARD 2 0 bis 65535
LONGCARD 4 0 bis 4294967295
INTEGER 2/4 vgl. SHORTINT / LONGINT und Option <i>
SHORTINT 2 -32768 bis 32767
LONGINT 4 -2147483648 bis 2147483647
CHAR 1 0C bis 377C (0 bis 255)
BOOLEAN 1 FALSE bis TRUE
POINTER 4 0 bis 4294967295
Unterbereich 1/2/4 je nach Größe (max. -2147483648 bis 2147483647)
======================================================================
!end_verbatim
!label TRUE
!label FALSE
Der Typ BOOLEAN ist definiert als BOOLEAN = (FALSE, TRUE). Es handelt
sich also um einen Aufzählungstyp, wobei TRUE für eine erfüllte
Bedingung steht.
!label NIL
Für Pointer existiert die Konstante NIL. Diese Konstante besitzt den
Wert 0 und dient als Kennzeichnung eines Pointers, der nirgends
hinzeigt. NIL ist zuweisungskompatibel zu allen Pointertypen.
!label REAL
!label SHORTREAL
!label LONGREAL
!begin_verbatim
======================================================================
Typ Größe Wertebereich min. Betrag
----------------------------------------------------------------------
REAL 4/8 vgl. SHORTREAL / LONGREAL und Option <r>
SHORTREAL 4 -3.402823E+38 bis 3.402823E+38 1.17549E-38
LONGREAL 8 -1.797693E+308 bis 1.797693E+308 2.225074E-308
======================================================================
!end_verbatim
Hänisch Modula-2 rechnet bei REAL-Typen (außer bei aktivierter Option
<f>, also direkter Verwendung des mathematischen Coprozessors) immer mit
LONGREALs. Das Rechnen mit SHORTREALs ist daher langsamer, da diese erst
in LONGREALs umgewandelt werden!
!label BYTESET
!label BITSET
!label LONGSET
!label CHARSET
!label SET OF
!label Aufzählung
!begin_verbatim
======================================================================
Typ Größe (maximale) Anzahl der Elemente
----------------------------------------------------------------------
BYTESET 1 8
BITSET 2 16
LONGSET 4 32
CHARSET 32 256
SET OF Type 1-4096 8-32768
Aufzählung 1/2 256/65535
======================================================================
!end_verbatim
Die Mengentypen sind wie folgt definiert:
!begin_verbatim
BYTESET = SET OF [0..7];
BITSET = SET OF [0..15];
LONGSET = SET OF [0..31];
CHARSET = SET OF CHAR;
!end_verbatim
Bei den Typen BYTESET, LONGSET und CHARSET handelt es sich um
HM2-Erweiterungen.
#*****************************************************************
!subsubnode STRING
Zusätzlich zu den bereits erläuterten Datentypen verfügt HM über den
Datentyp STRING. Strings sind zu den formalen Parametern ARRAY OF CHAR
kompatibel, haben aber keinen HIGH-Wert. Sie werden immer durch ein
Null-Byte (0C) abgeschlossen. Dieser Typ darf nur in der formalen
Parameterliste einer Prozedur benutzt werden. Der Datentyp STRING
erlaubt es, einem VAR-Parameter eine Konstate zu übergeben!
!begin_verbatim
PROCEDURE WriteStr (VAR Str: STRING);
BEGIN
END WriteStr;
BEGIN
WriteString ("Hello World!");
!end_verbatim
#*****************************************************************
!subnode Aggregate
Aggregate sind eine Zusammenfassung mehrerer Ausdrücke bzw. Werte zu
einem Record oder zu einem Array. Aggregate erlauben es, eine Record-
bzw. Array-Variable durch eine einzige Zuweisung komplett zu
initialisieren und ermöglichen die Deklaration strukturierter
Konstanten. Ein Aggregat wird eingeleitet durch einen Typnamen (Array-
oder Record-Typ). Diesem folgt, eingeschlossen in geschweifte Klammern,
die Aufzählung der Elemente. Tritt ein Aggregat als Element eines
anderen Aggregats auf, so kann die Angabe des Typnamens fehlen. Bei
Aggregaten eines Array-Typs kann bei den Elementen ein konstanter
Wiederholungsfaktor angegeben werden. Dieser wird mit "BY" an einen
Ausdruck angehängt. Der Ausdruck wird dabei nur einmal ausgewertet
(wichtig, falls der Ausdruck einen Prozeduraufruf enthält).
Beispiel:
!begin_verbatim
TYPE
tR = RECORD i: SHORTINT; ch: CHAR; b: BOOLEAN END;
tA = ARRAY [0..2] OF tR;
tA2 = ARRAY [0..9] OF SHORTINT;
CONST
cR = tR{-1, 'A', TRUE};
cA = tA2{-1 BY 3, 0, 1, 2, 3 BY 4};
VAR
A: tA;
i: SHORTINT;
ch: CHAR;
BEGIN
A := tA{cR, {i, 'B', i=0}, tR{i*i, ch, FALSE}};
!end_verbatim
#*****************************************************************
!subnode Standardprozeduren
Die nachfolgend aufgeführten Prozeduren sind immer vorhanden. Der Compiler
erzeugt bei ihrer Verwendung zum Teil direkt Code, d. h. es handelt sich
nicht um echte Prozeduren. Die Ergebnisse der Funktionsprozeduren können bei
konstanten Argumenten auch als Konstante verwendet werden.
#*****************************************************************
!subsubnode ABS
PROCEDURE ABS (x: Type): Type;
Diese Funktionsprozedur liefert den Absolutbetrag des übergebenen
Wertes. Die Argumente können ganze Zahlen oder Fließkommazahlen sein.
Der Ergebnistyp ist gleich dem Argumenttyp.
#*****************************************************************
!subsubnode CAP
PROCEDURE CAP (ch: CHAR): CHAR;
Diese Funktionsprozedur liefert für Kleinbuchstaben den zugehörigen
Großbuchstaben, für sonstige Zeichen das übergebene Zeichen. Es werden
nur die Zeichen 'a' bis 'z' berücksichtigt, keine nationalen
Sonderzeichen.
#*****************************************************************
!subsubnode CHR
PROCEDURE CHR (ord: CARDINAL): CHAR;
Diese Funktionsprozedur liefert das zur übergebenen Ordnungszahl
gehörende Zeichen. CHR (ord) ist identisch zu VAL (CHAR, ord).
#*****************************************************************
!subsubnode DEC
PROCEDURE DEC (x)
PROCEDURE DEC (x, n)
(vgl. INC)
Diese Prozedur verringert den Wert der übergebenen Variable um eins.
Optional kann ein zweiter Parameter angegeben werden. Dann wird die
Variable um den Wert des zweiten Parameters verringert.
Diese Prozedur kann auf Argumente verschiedenen Typs angewendet werden:
!begin_itemize
!item ganze Zahlen
!item Aufzählungstypen (auch BOOLEAN)
!item CHAR
!item Fließkommazahlen
!item Pointer
!end_itemize
Bei Aufzählungstypen erhält die Variable als Wert den (n-ten) Vorgänger.
Fließkommazahlen und Pointer als Argumente sind eine Erweiterung unter
Hänisch Modula-2. Bei Fließkommazahlen muß ein zweiter Parameter
vorhanden sein. Bei Pointern wird der Wert des Pointers nicht um 1 bzw.
n verringert, sondern um die (n-fache) Größe des Typs, auf den der
Pointer zeigt.
#*****************************************************************
!subsubnode DISPOSE
PROCEDURE DISPOSE (VAR Pointer)
Diese Prozedur gibt einen mit NEW allozierten Speicherberich wieder
frei. Dazu muß eine Prozedur DEALLOCATE deklariert sein. Diese kann man
von Storage importieren; man kann aber auch eine andere zur Verfügung
stellen. DISPOSE (p) ist identisch mit DEALLOCATE (p, SYSTEM.TSIZE (t)),
falls p als POINTER TO t deklariert ist (vgl. NEW).
#*****************************************************************
!subsubnode EXCL
PROCEDURE EXCL (Menge, Element)
Diese Prozedur entfernt ein Element aus einer Menge (vgl. INCL).
#*****************************************************************
!subsubnode FORM
PROCEDURE FORM (x1, ... , xn): STRING;
FORM dient zur String-Formatierung. Die Anzahl der Parameter ist
beliebig. Als Parameter können der Prozedur Zeichen, Zahlen und Strings
übergeben werden. Diese werden zu einem String zusammengefügt. Bei den
Parametern sind auch Formatangaben möglich. Diese folgen dem Parameter
durch ':' getrennt. Die Angaben haben folgende Bedeutung:
!begin_verbatim
bei ganzen Zahlen: Mindestbreite : Basis : Füllzeichen
bei REALs: Mindestbreite : Nachkommastellen : Füllzeichen bei
Strings: Mindestbreite : Füllzeichen
!end_verbatim
Für die einzelnen Angaben sind konstante Ausdrücke zulässig.
'Mindestbreite' und 'Nachkommastellen' dürfen im Bereich von -128 bis
127 liegen, Basis im Bereich von 2 bis 32. Negative Werte für die
Mindestbreite führen zu linksbündiger Ausgabe, positive zu
rechtsbündiger. Die einzelnen Formatangaben sind optional. Defaults:
!begin_verbatim
Mindestbreite 1
Basis 10
Nachkommastellen 0
Füllzeichen ' '
!end_verbatim
Beispiel:
!begin_verbatim
VAR
i: SHORTINT;
r: REAL;
s: ARRAY[0..10] OF CHAR;
c: CHAR;
Str: ARRAY [0..99] OF CHAR;
BEGIN
Str := FORM ("Wert: ", i:4:16:'0', " String: ", s:-8, " Zeichen: ",
c, " Real: ", r::5);
WriteString (Str);
!end_verbatim
'i' wird als 4-stellige Hexadezimalzahl mit führenden Nullen ausgegeben,
's' wird bis zu einer Gesamtlänge von 8 Zeichen hinten mit Leerzeichen
aufgefüllt und 'r' wird mit 5 Nachkommastellen ausgegeben.
FORM ist eine Erweiterung von Hänisch Modula-2.
#*****************************************************************
!subsubnode FLOAT
PROCEDURE FLOAT (Integer): LONGREAL;
Diese Funktionsprozedur wandelt eine ganze Zahl (d.h. INTEGER oder
CARDINAL) in eine Fließkommazahl (vgl. INT, TRUNC).
#*****************************************************************
!subsubnode HALT
PROCEDURE HALT
Bei Aufruf dieser Prozedur wird das Programm abgebrochen.
#*****************************************************************
!subsubnode HIGH
PROCEDURE HIGH (Array): LONGCARD;
Diese Funktionsprozedur liefert für offene Arrays (also
Prozedurparameter mit ARRAY OF Type als Typ) den größten zulässigen
Index für Zugriffe auf das übergebene Array. Wird z.B. die Prozedur
PROCEDURE p (open: ARRAY OF CHAR);
mit einem Array a: ARRAY [5..80] OF CHAR aufgerufen, so sind in der
Prozedur Zugriffe auf die Elemente open[0] bis open[HIGH(open)] zulässig
(HIGH(open) = 75).
#*****************************************************************
!subsubnode INC
PROCEDURE INC (x)
PROCEDURE INC (x, n)
(vgl. DEC)
Diese Prozedur erhöht den Wert der übergebenen Variable um eins.
Optional kann ein zweiter Parameter angegeben werden. Dann wird die
Variable um den Wert des zweiten Parameters erhöht.
Diese Prozedur kann auf Argumente verschiedenen Typs angewendet werden:
!begin_itemize
!item ganze Zahlen
!item Auzählungstypen (auch BOOLEAN)
!item CHAR
!item Fließkommazahlen
!item Pointer
!end_itemize
Bei Aufzählungstypen erhält die Variable als Wert den (n-ten)
Nachfolger. Fließkommazahlen und Pointer als Argumente sind eine
Erweiterung unter Hänisch Modula-2. Bei Fließkommazahlen muß ein zweiter
Parameter vorhanden sein. Bei Pointern wird der Wert des Pointers nicht
um 1 bzw. n erhöht, sondern um die (n-fache) Größe des Typs, auf den der
Pointer zeigt.
#*****************************************************************
!subsubnode INCL
PROCEDURE INCL (Menge, Element)
Diese Prozedur nimmt ein Element in eine Menge auf (vgl. EXCL).
#*****************************************************************
!subsubnode INT
PROCEDURE INT (x): LONGINT;
Diese Funktionsprozedur ist für ganzzahlige Typen identisch mit
VAL (LONGINT, x). Für REAL-Typen liefert sie den ganzzahligen Anteil einer
Fließkommazahl.
#*****************************************************************
!subsubnode LENGTH
PROCEDURE LENGTH (String: ARRAY OF CHAR): LONGINT;
Diese Funktionsprozedur liefert die Länge des übergebenen Strings unter
Berücksichtigung des HIGH-Wertes. Sie ist insbesondere interessant für die
Verwendung in konstanten Ausdrücken zur Längenbestimmung symbolischer
Stringkonstanten.
#*****************************************************************
!subsubnode LFLOAT
PROCEDURE LFLOAT (Integer): LONGREAL;
Diese Funktionsprozedur ist identisch mit FLOAT.
#*****************************************************************
!subsubnode MAX
PROCEDURE MAX (Type): Type;
Diese Funktionsprozedur liefert den Maximalwert des übergebenen Typs. Der
Ergebnistyp ist abhängig vom übergebenem Typ.
#*****************************************************************
!subsubnode MIN
PROCEDURE MIN (Type): Type;
Diese Funktionsprozedur liefert den Minimalwert des übergebenen Typs. Der
Ergebnistyp ist abhängig vom übergebenem Typ. Bei REAL-Typen wird der
kleinste darstellbare positive Wert geliefert.
#*****************************************************************
!subsubnode NEW
PROCEDURE NEW (VAR Pointer);
Diese Prozedur alloziert einen Speicherbereich mit der Größe des Typs, auf
den der Pointer zeigt. Dazu muß eine Prozedur ALLOCATE deklariert sein.
Diese kann man von Storage importieren; man kann aber auch eine andere zur
Verfügung stellen. NEW (p) ist identisch mit ALLOCATE (p,SYSTEM.TSIZE (t)),
falls p als POINTER TO t deklariert ist (vgl. DISPOSE).
#*****************************************************************
!subsubnode ODD
PROCEDURE ODD (Integer): BOOLEAN;
Diese Funktionsprozedur kann auf ganzzahlige Typen angwendet werden.
Sie liefert TRUE, falls der übergebene Wert ungerade ist, FALSE falls er
gerade ist.
#*****************************************************************
!subsubnode ORD
PROCEDURE ORD (x): LONGCARD;
ORD (x) ist identisch zu VAL (LONGCARD, x)
#*****************************************************************
!subsubnode SIZE
PROCEDURE SIZE (x): LONGCARD;
Diese Funktionsprozedur liefert die Anzahl von Bytes, die für die
übergebene Variable an Speicher benötigt werden. (vgl. SYSTEM.TSIZE)
#*****************************************************************
!subsubnode TRUNC
PROCEDURE TRUNC (real: LONGREAL): LONGCARD;
Diese Funktionsprozedur liefert den ganzzahligen Anteil einer
Fließkommazahl. Sie ist nur für positive Werte definiert (vgl. INT).
#*****************************************************************
!subsubnode VAL
PROCEDURE VAL (Type, x): Type;
Diese Funktionsprozedur liefert einen Wert vom Typ Type, der dem Wert von x
entspricht. Für einen Aufzählungstyp Farben = (rot, gruen, blau) gilt z.B.
VAL (Farben, 1) = gruen. Im Gegensatz zur [Typerzwingung] wird hier
gegebenenfalls Code erzeugt, um den Wert umzuwandeln und die Argumente
müssen nicht die gleiche Typgröße besitzen.
#*****************************************************************
!subsubnode VOID
PROCEDURE VOID (x);
Die Prozedur VOID akzeptiert einen Parameter beliebigen Typs, mit dem NICHTS
gemacht wird. Sinn der Sache ist es, die Zuweisung nicht benötigter
Funktionsrückgaben an Dummy-Variablen zu vermeiden.
Beispiel:
!begin_verbatim
VOID (form.alert (1, '[1][Eine Meldung!][AHA]');
!end_verbatim
VOID ist eine Erweiterung von Hänisch Modula-2.
#*****************************************************************
!subnode Das SYSTEM-Modul
!label SYSTEM
Das Pseudo-Modul SYSTEM wird nicht aus einer Objekt-Datei gelesen, sondern
ist bereits im Compiler integriert. Einige der Funktionen sind generisch
und haben keine vordefinierten Parameter. Im HM-Compiler sind folgende
Konstanten, Typen und Funktionen vorhanden:
!subsubtoc [html, stg]
#*****************************************************************
!subsubnode DATE
CONST DATE
Diese Konstante besitzt (beim Compilieren) als Wert das aktuelle Datum.
Die Konstante ist vom Typ LONGCARD; der Wert setzt sich wie folgt zusammen:
!begin_verbatim
tDate = RECORD
day: [0..31];
month: [1..12];
year: SHORTINT;
END;
!end_verbatim
#*****************************************************************
!subsubnode FLAG
CONST FLAG
Diese Konstante besitzt den Wert der Makevariable FLAG. Mit ihrer Hilfe
kann man von außen auf den Quelltext Einfluß zu nehmen (z.B. um
verschiedene Versionen eines Programmes zu erzeugen, vgl.
[Bedingte_Compilierung]).
#*****************************************************************
!subsubnode LINE
CONST LINE
Diese Konstante besitzt während des Compilierens als Wert jeweils die
aktuelle Zeilennummer. Damit kann man sich in (Debug-) Ausgaben auf eine
Zeile des Quelltextes beziehen.
#*****************************************************************
!subsubnode ADDRESS
TYPE ADDRESS
Dieser Typ ist als POINTER auf den Typ WORD definiert. Das besondere
Merkmal ist seine Kompatibilität mit dem Typ CARDINAL und allen anderen
Typen der Form POINTER TO. Adreßberechnungen sind somit auf Werten dieses
Typs möglich.
#*****************************************************************
!subsubnode LOC
TYPE LOC
Dieser Typ repräsentiert die kleinste adressierbare Speichereinheit.
!label BITSPERLOC
CONST BITSPERLOC = 8
!label LOCSPERBYTE
CONST LOCSPERBYTE = 1
!label LOCSPERWORD
CONST LOCSPERWORD = 2
TYPE BYTE = LOC
Dieser Typ hat eine Größe von einem Byte. Erlaubt ist nur die Zuweisung.
Parametern vom Typ BYTE können beliebige Typen mit einer Größe von einem
Byte übergeben werden. Definiert man einen Parameter als ARRAY OF BYTE, so
können diesem Parameter Variablen beliebigen Typs übergeben werden.
#*****************************************************************
!subsubnode WORD
TYPE WORD
Dieser Typ hat eine Größe von zwei Bytes. Erlaubt ist nur die Zuweisung.
Parametern vom Typ WORD können beliebige Typen mit einer Größe von zwei
Bytes übergeben werden.
#*****************************************************************
!subsubnode LONG
TYPE LONG
Dieser Typ hat eine Größe von vier Bytes. Erlaubt ist nur die Zuweisung.
Parametern vom Typ LONG können beliebige Typen mit einer Größe von vier
Bytes übergeben werden.
#*****************************************************************
!subsubnode SHIFT
PROCEDURE SHIFT (set: SetType; num: LONGINT): SetType;
Diese Funktion liefert als Ergebnis eine Menge, deren Elemente die von
'set' jeweils erhöht um 'num' sind.
Betrachtet man 'set' als Bitmuster, so wirkt SHIFT als logische
Verschiebung nach links oder rechts um ABS (num) Positionen; für 'num' > 0
wird nach links geschoben, sonst nach rechts.
#*****************************************************************
!subsubnode ROTATE
PROCEDURE ROTATE (set: SetType; num: LONGINT): SetType;
Betrachtet man 'set' als Bitmuster, so wirkt ROTATE als Rotation nach
links oder rechts um ABS (num) Positionen; für 'num' > 0
wird nach links rotiert, sonst nach rechts.
#*****************************************************************
!subsubnode MAKEADR
PROCEDURE MAKEADR (val: Type): ADDRESS;
Diese Funktion wandelt einen Wert in eine Adresse.
#*****************************************************************
!subsubnode ADDADR
PROCEDURE ADDADR (addr: ADDRESS; offset: LONGINT): ADDRESS;
Diese Funktion liefert die Adresse, die bei Addition des Offsets 'offset'
zur Adresse 'addr' entsteht.
#*****************************************************************
!subsubnode SUBADR
PROCEDURE SUBADR (addr: ADDRESS; offset: LONGINT): ADDRESS;
Diese Funktion liefert die Adresse, die bei Subtraktion des Offsets 'offset'
zur Adresse 'addr' entsteht.
#*****************************************************************
!subsubnode DIFADR
PROCEDURE DIFADR (addr1, addr2: ADDRESS): LONGINT;
Diese Funktion liefert die Differenz zweier Adressen.
#*****************************************************************
!subsubnode TSIZE
PROCEDURE TSIZE (x): LONGCARD;
Diese Funktion erwartet einen Typnamen als Parameter und liefert dessen
Größe in Byte zurück. Strukturierte Typen besitzen immer eine gerade Größe.
(vgl. SIZE)
#*****************************************************************
!subsubnode CAST
CAST (Type, x)
Diese Prozedur führt eine Typerzwingung durch. CAST (Type, x) ist identisch
mit Type (x). x erhält Type als Typ. Eine Typerzwingung ist nur für
Typen gleicher Größe möglich. (vgl. Typerzwingung)
#*****************************************************************
!subsubnode CODE
PROCEDURE CODE(c1, c2, ... , cn);
Diese Prozedur akzeptiert beliebig viele Parameter. Es dürfen nur
Konstanten übergeben werden, die der Reihe nach in die Instruktions-Sequenz
eingefügt werden. Für jeden Parameter wird ein Wort (16 Bit) eingesetzt.
Die eingesetzten Konstanten werden ggf. als Instruktionen vom Prozessor
verarbeitet. Daher ist größte Sorgfalt anzuwenden.
#*****************************************************************
!subsubnode LOAD
PROCEDURE LOAD (x: LONGINT; reg: SHORTCARD);
Diese Prozedur lädt den Wert des ersten Parameters in das angegebene
CPU-Register. Dabei haben die Register folgende Nummern:
!begin_verbatim
D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7
---------------------------------------
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
A0 | A1 | A2 | A3 | A4 | A5 | A6 | A7
---------------------------------------
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15
!end_verbatim
Sofern es sich bei dem Register nicht um ein Scratchregister handelt, so
wird es im Prozedurprolog automatisch gerettet und im Prozedurepilog
restauriert.
#*****************************************************************
!subsubnode STORE
PROCEDURE STORE (reg: SHORTCARD; VAR x: LONGINT);
Diese Prozedur schreibt den Inhalt des angegebenen CPU-Registers in die
übergebene Variable (vgl. LOAD).
#*****************************************************************
!subsubnode ADR
PROCEDURE ADR (x): ADDRESS;
Diese Funktion akzeptiert einen Parameter, der adressierbar sein muß. Sie
liefert die Adresse des Objektes zurück.
NB: Konstanten sind normalerweise nicht adressierbar. Insbesondere kann man
mittels ADR nicht die Adresse einer Prozedur ermitteln. Die Adresse einer
Prozedur kann mittels ADDRESSS (ProcName) ermittelt werden (also durch
Typerzwingung).
Unter HM2 kann mittels ADR auch die Adresse 'großer' Konstanten ermittelt
werden.
#*****************************************************************
!subsubnode NEWPROCESS
PROCEDURE NEWPROCESS (P: PROC; A: ADDRESS; n: LONGCARD; VAR p: ADDRESS);
Diese Prozedur erzeugt aus einer Prozedur eine Coroutine. Dazu wird am
unteren Ende des Stacks ein Prozeßblock angelegt. 'P' wird eine
parameterlose Prozedur übergeben. Über den Parameter 'A' wird eine
Speicherbereich der Größe 'n' zur Verfügung gestellt. In 'p' erhält man
einen Zeiger auf die Coroutine. Coroutinen dürfen nie ihr Ende erreichen!
#*****************************************************************
!subsubnode TRANSFER
PROCEDURE TRANSFER (VAR p1, p2: ADDRESS);
Um die Kontrolle von einer Coroutine 'p1' auf einen andere Coroutine 'p2'
übertragen, verwendet man die Prozedur TRANSFER.
#*****************************************************************
!subsubnode IOTRANSFER
PROCEDURE IOTRANSFER (VAR p1, p2: ADDRESS; v: LONGCARD);
Die Programmkontrolle wird über einen Interrupt auf eine bestimmte
Coroutine übertragen. Bei Aufruf von IOTRANSFER wird in 'p1' die gerade
aktive Coroutine gespeichert und die Kontrolle an die in Coroutine 'p2'
transferiert. Über 'v' wird der auslösende Interrupt festgelegt (0-255).
Wenn dieser zum nächsten Mal auftritt, so wird die aktuelle Coroutine
suspendiert, diese in 'p2' gespeichert und die Coroutine in 'p1' aktiviert.
Dies entspricht im wesentlichen dem Aufruf einer Coroutine über TRANSFER.
Der Interrupt bewirkt also nur die Einfügung einer TRANSFER- Anweisung in
den Programmablauf.
#*****************************************************************
!subnode FPU
Bei dem Modul FPU handelt es sich ebenso wie bei dem Modul SYSTEM um ein
Pseudo-Modul. Dieses Modul ist jedoch nur bei aktivierter
Compiler-Option <f> (Coprozessor) vorhanden. Es stellt die nachfolgend
aufgeführten Funktionen des mathematischen Coprozessors MC68881/882 zur
Verfügung. Bei Verwendung dieser Prozeduren wird Code erzeugt, der die
entsprechenden Coprozessor-Funktionen direkt verwendet.
!label PI
!label E
!label LN_2
!label LN_10
!label LOG2_E
!label LOG10_E
!label LOG10_2
!label EXTENDED
!label SIN
!label SINH
!label ASIN
!label COS
!label COSH
!label ACOS
!label TAN
!label TANH
!label ATAN
!label SQRT
!label ETOX
!label ETOXM1
!label TWOTOX
!label TENTOX
!label LOGN
!label LOGNP1
!label LOG10
!label LOG2
!begin_verbatim
CONST
PI (* π *)
E (* e *)
LN_2 (* natürlicher Logarithmus von 2 *)
LN_10 (* natürlicher Logarithmus von 10 *)
LOG2_E (* Zweierlogarithmus von e *)
LOG10_E (* Zehnerlogarithmus von e *)
LOG10_2 (* Zehnerlogarithmus von 2 *)
!end_verbatim
TYPE EXTENDED (* extended precision, kompatibel mit SHORTREAL und
LONGREAL *)
PROCEDURE SIN (x: EXTENDED): EXTENDED;
(* sin x *)
PROCEDURE SINH (x: EXTENDED): EXTENDED;
(* sinh x *)
PROCEDURE ASIN (x: EXTENDED): EXTENDED;
(* arc sin x *)
PROCEDURE COS (x: EXTENDED): EXTENDED;
(* cos x *)
PROCEDURE COSH (x: EXTENDED): EXTENDED;
(* cosh x *)
PROCEDURE ACOS (x: EXTENDED): EXTENDED;
(* arc cos x *)
PROCEDURE TAN (x: EXTENDED): EXTENDED;
(* tan x *)
PROCEDURE TANH (x: EXTENDED): EXTENDED;
(* tanh x *)
PROCEDURE ATAN (x: EXTENDED): EXTENDED;
(* arc tan x *)
PROCEDURE ATANH (x: EXTENDED): EXTENDED;
(* arc tanh x *)
PROCEDURE SQRT (x: EXTENDED): EXTENDED;
(* Quadratwurzel x *)
PROCEDURE ETOX (x: EXTENDED): EXTENDED;
(* e hoch x *)
PROCEDURE ETOXM1 (x: EXTENDED): EXTENDED;
(* (e hoch x) minus 1 *)
PROCEDURE TWOTOX (x: EXTENDED): EXTENDED;
(* 2 hoch x *)
PROCEDURE TENTOX (x: EXTENDED): EXTENDED;
(* 10 hoch x *)
PROCEDURE LOGN (x: EXTENDED): EXTENDED;
(* ln x *)
PROCEDURE LOGNP1 (x: EXTENDED): EXTENDED;
(* ln (x + 1) *)
PROCEDURE LOG10 (x: EXTENDED): EXTENDED;
(* Logarithmus Basis 10 *)
PROCEDURE LOG2 (x: EXTENDED): EXTENDED;
(* Logarithmus Basis 2 *)
Neben diesen Funktionen, die namentlich denen des mathematischen
Coprozessors entsprechen, gibt es noch die beiden folgenden Funktionen
zum Umwandeln von ganzen Zahlen in Fließkommazahlen und umgekehrt. Für
die Umwandlung wird die MOVE-Instruktion des mathematischen Coprozessors
benutzt. Die Rundung ist also abhängig von der eingestellten Rundung des
mathematischen Coprozessors.
!label EXTEND
PROCEDURE EXTEND (x: LONGINT): EXTENDED;
!label WHOLE
PROCEDURE WHOLE (x: EXTENDED): LONGINT;
#*****************************************************************
!subnode Registerbelegung
Die Register D0, D1, A0, A1 und FP0 werden als sogenannte Scratchregister
behandelt, d.h. sie müssen in Prozeduren nicht gerettet werden. Alle
anderen Register werden bei Verwendung in einer Prozedur im
Prozedurprolog gerettet und im Prozedurepilog wieder restauriert.
Funktionsprozeduren geben ihr Ergebnis in D0 bzw. D0/D1 oder FP0 zurück.
Dies gilt für Datentypen mit einer Größe von maximal 4 Bytes und für
LONGREALs. Größere Typen werden quasi als Referenzparameter behandelt.
Die Register D2 - D7, A2 - A4 und FP1 - FP7 stehen für Registervariablen
zur Verfügung.
Das Adreßregister A4 wird ggf. auch für WITH-Anweisungen benutzt.
Das Adreßregister A5 dient als Basiszeiger für die globalen Variablen
des Moduls. Bei Eintritt in eine exportierte Prozedur wird Register A5
gerettet und mit der Adresse des Modul-Datenbereiches geladen. In allen
anderen, nicht exportierten Prozeduren, ist Register A5 dann bereits
definiert und wird daher nicht neu geladen.
Das Adreßregister A6 dient als Basiszeiger für die lokalen Variablen und
die Parameter einer Prozedur. Der Bereich für die lokalen Variablen wird
bei Prozedureintritt auf dem Stack angelegt.
Das Adreßregister A7 dient als Stack-Pointer. Der Stack wächst, wie auf
680x0-Prozessoren üblich, von hohen Adressen in Richtung niedriger
Adressen. Bei aktivierter Compiler-Option $S wird beim Prozedureintritt
überprüft, ob der für den Stack vorgesehene Bereich noch für den lokalen
Datenbereich ausreicht oder ob ein Stacküberlauf eingetreten ist.
#*****************************************************************
!subnode Sonstiges
!subsubtoc [html, stg]
#*****************************************************************
!subsubnode Typerzwingung
Setzt man einen Typnamen vor einen geklammerten Ausdruck, so erhält der
Ausdruck diesen Typ. Dabei wird kein Code erzeugt. Die Typerzwingung ist
nur dann möglich, wenn die Größe des angegebenen Typs mit der Größe des
Typs des Ausdrucks übereinstimmt (vgl. VAL). Die Typerzwingung kann bei
HM an allen syntaktisch sinnvollen Stellen eingesetzt werden, auch auf
der linken Seite einer Zuweisung oder bei Referenzparametern (vgl.
SYSTEM.CAST). Beispiele:
!begin_verbatim
VAR
l: LONGINT;
b: BITSET;
proc: PROC;
PROCEDURE p (VAR a: ADDRESS);
(* ... *)
b := BITSET(SHORTINT(b)*2);
p (ADDRESS(l));
ADDRESS(proc) := NIL;
!end_verbatim
#*****************************************************************
!subsubnode Variablen an festen Adressen
Normalerweise liegen Variablen im Datenbereich des Programms und der
Programmierer hat keinen Einfluß auf die Adresse einer Variable im Speicher.
Unter HM ist es möglich, eine Variable an eine feste Adresse im Speicher zu
legen. Auf diese Weise lassen sich Systemvariablen und Hardware-Register
einfach ansprechen:
!begin_verbatim
VAR
a[456H], b: LONGINT;
BEGIN
b := a;
!end_verbatim
Das Beispiel zeigt den direkten Zugriff auf das Langwort an Adresse 456H. Die
Deklaration einer solchen Variable kann sowohl global als auch lokal in einer
Prozedur erfolgen (dies beeinflußt nur den Sichtbarkeitsbereich der
Variable). Innerhalb der eckigen Klammern wird ein konstanter Ausdruck
erwartet, der die Adresse der Variable festlegt.
#*****************************************************************
!subsubnode Rückgabewerte
Unter HM ist es möglich, daß Prozeduren einen RECORD- oder einen
ARRAY-Typ als Rückgabewert besitzen. Funktionen, die Zeiger oder
strukturierte Werte zurückgeben, dürfen direkt referenziert werden. So
ist z.B. ein Aufruf wie
!begin_verbatim
TYPE
tType = POINTER TO Type;
VAR
t: Type
BEGIN
t := xxx()^;
!end_verbatim
erlaubt, falls die Funktion xxx einen Zeiger auf den entsprechenden
Datentyp zurückgibt.
#*****************************************************************
!subsubnode Konstantendeklaration
Standardfunktionen, die Konstanten zurückliefern, wie z.B. die Funktion
TSIZE, dürfen auch in der Deklaration von Konstanten verwendet werden.
Der in einem konstanten Ausdruck verwendete Typ muß jedoch vorher deklariert
werden!
#*****************************************************************
!subsubnode Konkatenation von String- und Zeichenkonstanten
HM2 erlaubt die Konkatenation, also das Aneinanderhängen bzw. die
Verkettung, von String- und Zeichenkonstanten zu Stringkonstanten. Dazu
werden beliebig viele String- und/oder Zeichenkonstanten mittels '+'
miteinander verbunden. Beispiel:
!begin_verbatim
CONST
cVersion = '1.00';
cCR = 15C;
cLF = 12C;
cNl = cCR + cLF;
cMsg = 'Dies ist Version ' + cVersion + cNl;
!end_verbatim
#*****************************************************************
!subsubnode Kontrollstrukturen
In Schleifen sind die Anweisungen BREAK und CONTINUE erlaubt. BREAK
bricht die Schleife ab, während CONTINUE die Berechnung mit dem nächsten
Schleifendurchlauf fortsetzt. CONTINUE ist auch in der CASE-Anweisung
erlaubt. Die Berechnung wird dann an der nächstliegenden Fallauswahl
fortgesetzt.
#*****************************************************************
!subnode Kommandozeile
Die Syntax der Kommandozeile sieht folgendermaßen aus (man erhält sie
auch durch den Aufruf "HM -h"):
!begin_verbatim
HM [-bcilnosu] [MakeFile]
{[-z [MainModule]] [-v {MakeVar=Value}]}
{-r[a] {RemoveModule}}
{-p[g] {CheckPath}}
{-d {DefModule|DefPath}}
{-m {ImpModule|ImpPath}}
!end_verbatim
(!B)Direktiven(!b)
Direktiven sind Schalter, die das Verhalten des Compilers verändern.
Nicht verändert wird aber der erzeugte Code.
!begin_verbatim
b - nicht Build durchführen
c - nicht linken
(kommt übrigens von *IX: nur C-Compiler -> nicht linken!)
i - bei Make-Lesen und -Sichern Dateinamen interaktiv erfragen
l - am Ende Liste der Modulzustände ausgeben
n - NonStop - bei Fehlern nicht anhalten (für Batchbetrieb)
o - jedes 'o' vergrößert Makespeicher um 16 kByte
(nicht in ACC-Version)
s - Make-Datei am Ende auch sichern, wenn keine Änderung
festgestellt wird
u - TOS: Pfadnamen NICHT in Großbuchstaben konvertieren
sonst: Pfadnamen DOCH in Großbuchstaben konvertieren
!end_verbatim
!stg @symbol MakeFile
(!B)MakeFile(!b)
enthält den Namen der Makedatei. Wird am Dateisuffix
erkannt, muß daher in Groß-/Kleinschreibung korrekt sein (unter TOS
groß, also ".HM2"!)
!stg @symbol -z
(!B)-z (MainModule)(!b) (Choo(!B)Z(!b)e)
Setzt das Hauptmodul, auf das sich Optionseinstellungen beziehen und aus
dem das Hauptprogramm erstellt wird. Ohne Angabe eines Modulnamens ist
anschließend kein Hauptmodul aktiv, nachfolgende Optionsangaben setzen
die Defaulteinstellungen.
N.B.: Laut Syntax können (wegen {[-z...] [-v...]}) in einem Aufruf die
Optionen für mehrere Hauptmodule gesetzt werden.
!stg @symbol -v
(!B)-v {MakeVar=Value}(!b) (Variable)
Die in der Makedatei angebbaren Variablen können hier umdefiniert werden:
!begin_verbatim
MOPT Make-Optionen
MAIN Hauptmodul
Auf das aktive Hauptmodul beziehen sich:
COPT Compiler-Optionen
COMP Speicher für Compiler
FLAG SYSTEM.FLAG für Compiler
LOPT Linker-Optionen
STACK Stackgröße für gelinktes Programm
LINK Speicher für Linker
EXT Suffix für gelinktes Programm (samt Punkt, z.B. "EXT=.PRG")
PROG Größe für Programmspeicher beim Linken
DEST Zielsystem (0=TOS, 1=MINIX, 2=RTOS, ...)
TOS TOS-Spezifisches
RTOS RTOS-Spezifisches
!end_verbatim
!stg @symbol -r
(!B)-r[a] {RemoveModule}(!b) (Remove/Archive)
Entfernt Modul(e) aus dem Make. Mit dem Zusatz a werden bei Objekten in
Archiven alle Module in diesem Archiv auf einmal entfernt, also z.B.
"-ra Terminal" entfernt alle Module aus STD.A.
!stg @symbol -p
(!B)-p[g] {CheckPath}(!b) (Path/Generate)
Meldet Dateien in das Make an. Die Angabe erfolgt über Dateinamen mit
oder ohne Wildcards, oder durch mit '\' bzw. '/' abgeschlossene
Pfadnamen. Ohne den Zusatz g (generate) werden nur vorhandene Einträge
überprüft, mit dem Zusatz g werden auch neue eingetragen.
Werden keine Pfade angegeben, werden sämtliche dem Make bekannten Pfade
neu eingecheckt.
!stg @symbol -d
(!B)-d {DefModule|DefPath}(!b) (Definition)
Übersetzt die DEFINITION MODULEs. Die Angabe kann durch den Modulnamen
oder durch den Pfadnamen (bzw. ein Suffix davon) erfolgen. Werden keine
Module angegeben, werden alle ungültigen Def.-Module dieses Projekts
übersetzt.
!stg @symbol -m
(!B)-m {ImpModule|ImpPath}(!b) (imp. Module)
Übersetzt die IMPLEMENTATION MODULEs. Die Angabe kann durch den
Modulnamen oder durch den Pfadnamen (bzw. ein Suffix davon) erfolgen.
Werden keine Module angegeben, werden sämtliche Imp.-Module dieses
Projekts übersetzt, egal ob gültig oder nicht.
# Ende des Dokuments.